﻿using System;
using System.Collections.Generic;
using System.Text;

namespace Hockey.Shared
{
    /// <summary>
    /// Pub/Sub pattern implementation
    /// </summary>
    public static class Msg
    {
        /// <summary>
        /// Event collections
        /// </summary>
        private static Dictionary<string, List<Action<object>>> mEvents;
        private static Dictionary<string, List<Action<object>>> mEventsWithParam;

        /// <summary>
        /// Static constructor
        /// </summary>
        static Msg()
        {
            mEvents = new Dictionary<string, List<Action<object>>>();
            mEventsWithParam = new Dictionary<string, List<Action<object>>>();
        }

        #region Posting methods

        public static void Post(string message)
        {
            InvokeEvent(message);
        }

        public static void PostP(string message, object param)
        {
            InvokeEventWithParam(message, param);
        }

        public static void PostT<T>(string message, T param)
        {
            PostP(message, param);
        }

        #endregion

        #region Subscribing methods

        public static void Subscribe(string message, Action<object> handler)
        {
            CheckEventCreated(message);
            mEvents[message].Add(handler);
        }

        public static void SubscribeP(string message, Action<object> handler)
        {
            CheckEventCreatedWithParam(message);
            mEventsWithParam[message].Add(handler);
        }
       
        /// <summary>
        /// Checks whether an event is created
        /// </summary>
        private static void CheckEventCreated(string message)
        {
            List<Action<object>> handlers;
            try
            {
                handlers = mEvents[message];

                // for Java compilation compatibility
                if (handlers == null)
                    throw new Exception(string.Empty);
            }
            catch
            {
                handlers = new List<Action<object>>();
                mEvents[message] = handlers;
            }
        }

        /// <summary>
        /// Checks whether an event is created
        /// </summary>
        private static void CheckEventCreatedWithParam(string message)
        {
            List<Action<object>> handlers;
            try
            {
                handlers = mEventsWithParam[message];

                // for Java compilation compatibility
                if (handlers == null)
                    throw new Exception(string.Empty);
            }
            catch
            {
                handlers = new List<Action<object>>();
                mEventsWithParam[message] = handlers;
            }
        }

        #endregion

        #region Invoking methods

        /// <summary>
        /// Invoke event with given message
        /// </summary>
        private static void InvokeEvent(string message)
        {
            try
            {
                // get the event
                List<Action<object>> handlers = mEvents[message];

                // iterate them
                foreach(Action<object> handler in handlers)
                {
                    handler(null);
                }
            }
            catch
            { 
            }
        }

        /// <summary>
        /// Invoke event with param
        /// </summary>
        private static void InvokeEventWithParam(string message, object param)
        {
            try
            {
                // get the event
                List<Action<object>> handlers = mEventsWithParam[message];

                // iterate them
                foreach (Action<object> handler in handlers)
                {
                    handler(param);
                }
            }
            catch
            {
            }
        }

        #endregion
    }
}
